package concurrent.blockingQueue;

import org.junit.Test;

import java.util.NoSuchElementException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * ArrayBlockingQueue是一个由数组实现的循环阻塞队列
 * add/remove/element 当满或者没有元素时会报错
 * offer/pull/peek 不会报错，只会返回false或者null
 * put/take 阻塞版本，当满了或者没有元素会阻塞
 * offer(e,time,unit)/pull(time,unit) 可以设置超时时间
 * @author tuyou
 * @date 2020-08-18 21:40:07
 */
public class ArrayBlockingQueueTest {

    /**
     * 测试超出容量，调用add报错
     */
    @Test(expected = IllegalStateException.class)
    public void testAdd() {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        queue.add(1);
        queue.add(2);
        queue.add(3);
        queue.add(4);
    }

    /**
     * 测试超出容量，调用offer返回false
     */
    @Test
    public void testOffer() {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        System.out.println(queue.offer(1));
        System.out.println(queue.offer(2));
        System.out.println(queue.offer(3));
        System.out.println(queue.offer(4));
        System.out.println("完毕");
    }

    /**
     * 测试超出容量，调用put发生阻塞
     */
    @Test
    public void testPut() throws InterruptedException {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        queue.put(1);
        queue.put(2);
        queue.put(3);
        System.out.println("已满");
        queue.put(4);
        System.out.println("完毕");
    }

    /**
     * 测试没有元素，remove报错
     */
    @Test(expected = NoSuchElementException.class)
    public void testRemove() {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        queue.remove();
    }

    @Test
    public void test() {
        ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
        queue.stream();
    }

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        Thread t1 = new Thread(producer);
        Thread t2 = new Thread(consumer);
        t1.start();
        t2.start();

        Thread.sleep(1000);
    }

    static class Producer implements Runnable{

        protected BlockingQueue<String> queue = null;

        public Producer(BlockingQueue<String> queue){

            this.queue = queue;
        }

        @Override
        public void run() {

            try {
                queue.put("1");
                Thread.sleep(1000);
                queue.put("2");
                Thread.sleep(1000);
                queue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class Consumer implements Runnable{

        protected BlockingQueue<String> queue = null;

        public Consumer(BlockingQueue<String> queue){

            this.queue = queue;
        }

        @Override
        public void run() {

            try {
                System.out.println(queue.take());
                System.out.println(queue.take());
                System.out.println(queue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
